package com.myblog.myblog.interceptor;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;


/**
 * @author gyl
 * @data 2019/12/05 11:35
 */
@Aspect
@Order(1)
@Component
public class SystemLogAspect {

    /**
     * 定义切点表达式：*，第一个返回值，第二个类名，第三个方法名
     */
    @Pointcut("execution(public * com.myblog.myblog.controller.*.*(..))")
    /**使用一个返回值为void，方法体为空的方法来命名切入点*/
    public void sysPointCut(){}

    private final Logger logger = LoggerFactory.getLogger(this.getClass());


    @Before("sysPointCut()")
    public void sysBefore(JoinPoint joinPoint){
        logger.info("");
        logger.info("");
        logger.info("");
        logger.info("----------------before------------------");
        logger.info("前置通知：模拟执行权限检查...");
        logger.info("目标类是={}", joinPoint.getTarget());
        logger.info("被植入增强目标为={}", joinPoint.getSignature());

        ServletRequestAttributes attributes= (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request =attributes.getRequest();
        //url
        logger.info("请求路径URL={}",request.getRequestURL());
        //method
        logger.info("请求方式Method={}",request.getMethod());
        //ip
        logger.info("请求IP={}",request.getRemoteAddr());
        //类方法
        logger.info("请求类方法ClassMethod={}",joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
        //参数
        logger.info("请求参数Args={}",joinPoint.getArgs());
    }

    @AfterReturning(returning = "objects", pointcut = "sysPointCut()")
    public void sysAfterReturing(Object objects){
        logger.info("-----------@AfterReturning 后置通知-----------");
        logger.info("后置通知：模拟记录日志...");
        logger.info("返回值 response={}", objects);
    }

    /**
     * 环绕通知
     * @param proceedingJoinPoint 是JoinPoint的子接口，表示可以执行目标方法
     * @return Object
     * 必须接收一个参数，类型为ProceedingJoinPoint
     * @必须 throws Throwable
     */
    @Around("sysPointCut()")
    public Object sysAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        //开始
//        logger.info("-----------@Around 环绕通知start-----------");
//        long time = System.currentTimeMillis();
        Object object = proceedingJoinPoint.proceed();
//        time = System.currentTimeMillis() - time;
//        logger.info("方法用时Time={}",time+"毫秒");
//        logger.info("-----------@Around 环绕通知end-----------");
        return object;
    }

    @AfterThrowing(value = "sysPointCut()", throwing = "e")
    public void sysThrowing(JoinPoint joinPoint,Throwable e){
        logger.info("-----------@AfterThrowing 异常通知-----------");
        logger.info("异常通知：出错了"+ e);
//        logger.info("异常通知：出错了getStackTrace={}", e.getStackTrace());
        logger.info("异常通知：出错了Throwable...具体如下", e);
    }

    /**最终通知*/
    @After("sysPointCut()")
    public void myAfter() {
//        logger.info("-----------@After 最终通知-----------");
//        logger.info("最终通知：模拟方法结束后的释放资源...");
    }
}
